home *** CD-ROM | disk | FTP | other *** search
/ ftp.mactech.com 2010 / ftp.mactech.com.tar / ftp.mactech.com / machack / Hacks97 / ContextWarrior.sit / ContextWarrior / source code / ContextWarrior.c < prev    next >
C/C++ Source or Header  |  1997-06-28  |  10KB  |  388 lines

  1. // ContextWarrior
  2. // MacHack 97
  3. // Graham Herrick
  4. // this file is public domain
  5.  
  6. #include <SetUpA4.h>
  7. #include <A4Stuff.h>
  8. #include <AppleGuide.h>
  9. #include <Speech.h>
  10. #include "ContextualMenu.h"
  11. #include "MoreFilesExtras.h"
  12.  
  13. #define kInitID                128
  14. #define kCWFileMenuID        0x81
  15. #define kCWEditMenuID        0x82
  16. #define kCWSearchMenuID        0x83
  17. #define kCWProjectMenuID    0x85
  18. #define kCWWindowMenuID        0x84
  19. #define kCWHelpMenuID        0xBF96
  20.  
  21. enum
  22. {
  23.     kNowhere,                // this goes to file menu
  24.     kProjWindowContent,        // map this to project menu
  25.     kNormWindowContent,        // map this to edit menu?
  26.     kToolWindowContent,        // this goes to search menu
  27.     kWindowStructure        // map this to window menu and/or file menu
  28. };
  29.  
  30. typedef pascal void (*IMType)(void);
  31. typedef pascal long (*MSType)(Point pt);
  32.  
  33. typedef struct
  34. {
  35.     MenuHandle    menuoH;
  36.     short        menuLeft;
  37. } MenuRec;
  38.  
  39. typedef struct
  40. {
  41.     short    lastMenu,
  42.             lastRight,
  43.             mbResID;
  44.     MenuRec    menus[];
  45. } MenuList, *MenuListPtr, **MenuListHdl;
  46.  
  47. void        *gOldJGNE;
  48. IMType        gOldInitMenus;
  49. MSType        gOldMenuSelect;
  50. Boolean        inJGNE;
  51. Boolean        fakingAThing;
  52. Boolean        hasCM,cmChecked,hasSpeech,speechChecked;
  53. long        fakeResult;
  54. short        oldMenuID;
  55. FSSpec        gFileSpec;
  56. short        helpStage;
  57. Str255        helpMess;
  58.  
  59. pascal asm void myJGNE(void);
  60. pascal asm void NewInitMenusShell(void);
  61. pascal asm long NewMenuSelectShell(Point pt);
  62. long NewMenuSelect(Point pt);
  63. Boolean myGNE(EventRecord *event, Boolean preResult);
  64. MenuHandle GetCopyOfMenuWithThisID(short id, short newID);
  65. void NewInitMenus(void);
  66. Boolean ThisIsCodeWarrior(void);
  67. short WhereIsTheMouse(Point pt);
  68. void pStrCopy(StringPtr p1, StringPtr p2);
  69.  
  70. void main(void)
  71. {
  72.     long    oldA4;
  73.     Handle    theInit = 0L;
  74.     OSErr    myErr;
  75.     long    result;
  76.     
  77.     oldA4 = SetCurrentA4();
  78.     RememberA4();
  79.     myErr = Gestalt(gestaltSystemVersion,&result);
  80.     if(myErr || (LoWord(result) < 0x0800)) goto fail;
  81.     theInit = Get1Resource('INIT',kInitID);
  82.     if(!theInit) goto fail;
  83.     fakingAThing = inJGNE = hasCM = cmChecked = hasSpeech = speechChecked = false;
  84.     helpStage = 0;
  85.     gFileSpec.name[0] = 0;
  86.     gOldJGNE = LMGetGNEFilter();
  87.     gOldInitMenus = (IMType)GetToolTrapAddress(_InitMenus);
  88.     gOldMenuSelect = (MSType)GetToolTrapAddress(_MenuSelect);
  89.     LMSetGNEFilter(myJGNE);
  90.     SetToolTrapAddress((UniversalProcPtr)NewInitMenusShell,_InitMenus);
  91.     SetToolTrapAddress((UniversalProcPtr)NewMenuSelectShell,_MenuSelect);
  92.     DetachResource(theInit);
  93.     goto exit;
  94. fail:
  95.     SysBeep(10);
  96.     SysBeep(10);
  97.     SysBeep(10);
  98.     if(theInit) ReleaseResource(theInit);
  99. exit:
  100.     RestoreA4(oldA4);
  101. }
  102.  
  103. pascal asm long NewMenuSelectShell(Point pt)
  104. {
  105.     movem.l        a0-a3/a6-a7/d0-d7,-(sp)        
  106.     JSR            SetUpA4
  107.     MOVE.L        D0,D3                        // res(4),pt(4),rtn(4),reg(38)
  108.     MOVE.L        0x003C(sp),-(sp)            // res(4),pt(4),rtn(4),reg(38),pt(4)
  109.     JSR            NewMenuSelect
  110.     MOVE.L        D0,d2                        // res(4),pt(4),rtn(4),reg(38),pt(4)
  111.     MOVE.L        d3,D0
  112.     EXG            D0,A4
  113.     addq.w        #4,sp
  114.     MOVE.L        d2,0x0040(sp)                // res(4),pt(4),rtn(4),reg(38)
  115.     movem.l        (sp)+,a0-a3/a6-a7/d0-d7        // res(4),pt(4),rtn(4)
  116.     RTD            #4
  117. }
  118.  
  119. long NewMenuSelect(Point pt)
  120. {
  121.     long result;
  122.     
  123.     if(ThisIsCodeWarrior() && fakingAThing && pt.v == 10 && pt.v == 10)
  124.     {
  125.         fakingAThing = false;
  126.         result = fakeResult;
  127.     }
  128.     else result = gOldMenuSelect(pt);
  129.     return result;
  130. }
  131.  
  132. void NewInitMenus(void)
  133. {
  134.     if (ThisIsCodeWarrior())
  135.     {
  136.         OSErr    myErr;
  137.         short    mwRefNum = CurResFile();
  138.         FSSpec    dirSpec, gdirSpec;
  139.         long    gdparID;
  140.         Boolean    isDir;
  141.         
  142.         if(!speechChecked)
  143.         {
  144.             myErr = Gestalt(gestaltSpeechAttr,&gdparID);
  145.             if (!myErr && (gdparID & (1<<gestaltSpeechMgrPresent))) hasSpeech = true;
  146.             speechChecked = true;
  147.         }
  148.         if (!cmChecked)
  149.         {
  150.             myErr = Gestalt(gestaltContextualMenuAttr,&gdparID);
  151.             if (!myErr && (gdparID & (1<<gestaltContextualMenuTrapAvailable))) hasCM = true;
  152.             cmChecked = true;
  153.         }
  154.         if(hasCM)
  155.         {
  156.             InitContextualMenus();
  157.             helpStage = 0;
  158.             myErr = Gestalt(gestaltHelpMgrAttr,&gdparID);
  159.             if (!myErr && (gdparID & (1<<gestaltAppleGuidePresent)))
  160.             {
  161.                 myErr = FSpGetFileLocation(mwRefNum,&dirSpec);
  162.                 if(!myErr) myErr = FSMakeFSSpec(dirSpec.vRefNum,dirSpec.parID,
  163.                         "\p(CodeWarrior Guides)",&gdirSpec);
  164.                 if(!myErr) myErr = FSpGetDirectoryID(&gdirSpec,&gdparID,&isDir);
  165.                 if(!myErr) myErr = FSMakeFSSpec(gdirSpec.vRefNum,gdparID,
  166.                         "\pCodeWarrior IDE Guide",&gFileSpec);
  167.             }
  168.         }
  169.     }
  170. }
  171.  
  172. pascal asm void NewInitMenusShell(void)
  173. {
  174.     movem.l        a0-a3/a6-a7/d0-d7,-(sp)
  175.     subq.w        #4,sp
  176.     jsr            SetUpA4
  177.     move.l        d0,(sp)
  178.     jsr            NewInitMenus
  179.     movea.l        gOldInitMenus,a0
  180.     jsr            (a0)
  181.     move.l        (sp),d0
  182.     exg            d0,a4
  183.     addq.w        #4,sp
  184.     movem.l        (sp)+,a0-a3/a6-a7/d0-d7
  185.     rts
  186. }
  187.  
  188. pascal asm void myJGNE(void)
  189. {
  190.     MOVE.L        D0,A0            // save pre-result from SetUpA4
  191.     JSR            SetUpA4            // fix A4, stomp D0
  192.     MOVE.L        D0,-(A7)        // save old A4
  193.     MOVE.L        A0,D0            // restore pre-result
  194.     TST.B        inJGNE            // is myJGNE busy?
  195.     BNE            @1                // yes, so bail
  196.     MOVE.B        #true,inJGNE    // mark myJGNE busy
  197.     MOVE.W        D0,-(A7)        // push pre-result
  198.     MOVE.L        A1,-(A7)        // push event record pointer
  199.     JSR            myGNE            // do the real work
  200.     MOVE.L        (A7)+,A1        // restore event record pointer
  201.     ADDQ.L        #2,A7            // pop pre-result; post-result in D0
  202.     ASL.W        #8,D0            // bump C boolean to Lisa
  203.     MOVE.W        D0,8(A7)        // stash result where caller expects it
  204.     MOVE.B        #false,inJGNE    // mark myJGNE not busy
  205. @1:
  206.     MOVE.L        gOldJGNE,A0        // get previous jGNE
  207.     MOVE.L        (A7)+,A4        // restore A4
  208.     cmp.l        #0,a0
  209.     beq            bail
  210.     MOVE.L        A0,-(A7)        // return to previous jGNE
  211. bail:
  212.     RTS
  213. }
  214.  
  215. Boolean myGNE(EventRecord *event, Boolean preResult)
  216. {
  217.     Boolean postResult = preResult;
  218.  
  219.     if (preResult)
  220.     {
  221.         if (event->what == mouseDown || event->what == mouseUp && ThisIsCodeWarrior() &&
  222.             cmChecked && hasCM)
  223.         {
  224.             if(IsShowContextualMenuClick(event))
  225.             {
  226.                 MenuHandle    fileMenu;
  227.                 short        theID, place = WhereIsTheMouse(event->where);
  228.                 
  229.                 switch(place)
  230.                 {
  231.                     case kProjWindowContent:    theID = kCWProjectMenuID;    break;
  232.                     case kNormWindowContent:    theID = kCWEditMenuID;        break;
  233.                     case kWindowStructure:        theID = kCWWindowMenuID;    break;
  234.                     case kToolWindowContent:    theID = kCWSearchMenuID;    break;
  235.                     case kNowhere:
  236.                     default:                    theID = kCWFileMenuID;        break;
  237.                 }
  238.                 fileMenu = GetCopyOfMenuWithThisID(theID,theID+5678);
  239.                 
  240.                 if(fileMenu)
  241.                 {
  242.                     unsigned long    selType;
  243.                     short            selMenuID;
  244.                     unsigned short    selMenuItem;
  245.                     OSErr            myErr;
  246.                     
  247.                     InsertMenu(fileMenu,hierMenu);
  248.                     if(helpStage>0 && helpStage<4)
  249.                         myErr = ContextualMenuSelect(fileMenu,event->where,false,
  250.                                     kCMHelpItemOtherHelp,helpMess,0L,&selType,
  251.                                     &selMenuID,&selMenuItem);
  252.                     else
  253.                         myErr = ContextualMenuSelect(fileMenu,event->where,false,
  254.                                     kCMHelpItemAppleGuide,"\p",0L,&selType,
  255.                                     &selMenuID,&selMenuItem);
  256.                     DeleteMenu(theID+5678);
  257.                     DisposeHandle((Handle)fileMenu);
  258.                     if (selMenuID==theID+5678) selMenuID = theID;
  259.                     if (!myErr && selType == kCMMenuItemSelected)
  260.                     {
  261.                         fakeResult = ((long)selMenuID << 16) & 0xFFFF0000;
  262.                         fakeResult |= (selMenuItem & 0x0000FFFF);
  263.                         fakingAThing = true;
  264.                         // should find a better way to put mouse in menu bar
  265.                         event->where.h = event->where.v = 10;
  266.                     }
  267.                     else if (!myErr && selType == kCMShowHelpSelected)
  268.                     {
  269.                         AGRefNum    agRes;
  270.                         
  271.                         if(helpStage==0)
  272.                         {
  273.                             helpStage=1;
  274.                             pStrCopy("\pReal warriors don't need help",helpMess);
  275.                             if (hasSpeech) SpeakString(helpMess);
  276.                         }
  277.                         else if (helpStage==1)
  278.                         {
  279.                             helpStage++;
  280.                             pStrCopy("\pMaybe you're a virtual warrior",helpMess);
  281.                             if (hasSpeech) SpeakString(helpMess);
  282.                         }
  283.                         else if (helpStage==2)
  284.                         {
  285.                             helpStage++;
  286.                             pStrCopy("\pOr a CodePeacenik™",helpMess);
  287.                             if (hasSpeech) SpeakString(helpMess);
  288.                         }
  289.                         else if (helpStage==3)
  290.                         {
  291.                             helpStage++;
  292.                             pStrCopy("\pOkay. Here's some help.",helpMess);
  293.                             if (hasSpeech) SpeakString(helpMess);
  294.                             if (gFileSpec.name[0]) goto thing;
  295.                         }
  296.                         else if (gFileSpec.name[0])
  297.                         {
  298. thing:
  299.                             helpStage++;
  300.                             if(helpStage>15) helpStage = 0;
  301.                             switch(place)
  302.                             {
  303.                                 case kProjWindowContent:
  304.                                     myErr = AGOpenWithSearch(&gFileSpec,0,nil,"\pprojects",&agRes);
  305.                                     break;
  306.                                 case kWindowStructure:
  307.                                     myErr = AGOpenWithSearch(&gFileSpec,0,nil,"\pcredits",&agRes);
  308.                                     break;
  309.                                 case kToolWindowContent:
  310.                                     myErr = AGOpenWithSearch(&gFileSpec,0,nil,"\ptoolbar",&agRes);
  311.                                     break;
  312.                                 case kNormWindowContent:
  313.                                 case kNowhere:
  314.                                 default:
  315.                                     myErr = AGOpenWithView(&gFileSpec,0,nil,kAGViewTopicAreas,&agRes);
  316.                                     break;
  317.                             }
  318.                         }
  319.                         event->what = nullEvent;
  320.                         postResult = false;
  321.                     }
  322.                     else postResult = false;
  323.                 }
  324.             }
  325.         }
  326.     }
  327.     return postResult;
  328. }
  329.  
  330. MenuHandle GetCopyOfMenuWithThisID(short id, short newID)
  331. {
  332.     MenuListHdl        theMList = (MenuListHdl)LMGetMenuList();
  333.     short            numMenus,i;
  334.     MenuHandle        aMenu;
  335.     
  336.     if(!theMList || !*theMList) return 0L;
  337.     numMenus = (*theMList)->lastMenu/6;
  338.     for(i=0;i<numMenus;i++)
  339.     {
  340.         aMenu = (*theMList)->menus[i].menuoH;
  341.         if (aMenu && HandleZone((Handle)aMenu) && !MemError() && *aMenu && (*aMenu)->menuID == id)
  342.         {
  343.             HandToHand(&((Handle)aMenu));
  344.             (*aMenu)->menuID = newID;
  345.             return aMenu;
  346.         }
  347.     }
  348.     return 0L;
  349. }
  350.  
  351. Boolean ThisIsCodeWarrior(void)
  352. {
  353.     return EqualString(LMGetCurApName(),"\pCodeWarrior IDE 2.0",true,true);
  354. }
  355.  
  356. short WhereIsTheMouse(Point pt)
  357. {
  358.     WindowPeek frontWind = (WindowPeek)LMGetWindowList();
  359.     
  360.     while(frontWind)
  361.     {
  362.         if(PtInRgn(pt,frontWind->strucRgn))
  363.         {
  364.             if(PtInRgn(pt,frontWind->contRgn))
  365.             {
  366.                 Str255    title;
  367.                 
  368.                 if(frontWind->windowKind==0x4E21)
  369.                     return kNormWindowContent;
  370.                 GetWTitle((WindowPtr)frontWind,title);
  371.                 if(EqualString("\pToolbar",title,true,true))
  372.                     return kToolWindowContent;
  373.                 return kProjWindowContent;
  374.             }
  375.             return kWindowStructure;
  376.         }
  377.         frontWind = frontWind->nextWindow;
  378.     }
  379.     return kNowhere;
  380. }
  381.  
  382. void pStrCopy(StringPtr p1, StringPtr p2)
  383. {
  384.     BlockMoveData((Ptr)p1,(Ptr)p2,*p1+1);
  385. }
  386.  
  387.  
  388.